package cn.seaboot.admin.quartz.core;

import cn.seaboot.admin.quartz.bean.ScheduleJob;
import cn.seaboot.commons.lang.Warning;
import io.swagger.v3.oas.annotations.media.Schema;
import org.jetbrains.annotations.NotNull;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.utils.Key;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.function.Consumer;

/**
 * 一个较为通用的 job-builder
 * <p>
 * 可以满足大部分业务场景使用需求
 *
 * @author Mr.css
 * @version 2025-04-29 15:17
 */
public class QuartzJobBuilder {
    private final Logger logger = LoggerFactory.getLogger(QuartzJobBuilder.class);

    /**
     * 日期格式化，可以将 datetime 转换成 cron 表达式
     */
    private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("ss mm HH dd MM ? yyyy");

    /**
     * 调度器
     */
    private Scheduler scheduler;

    /**
     * JOB 全类名
     */
    private Class<? extends Job> clazz;

    /**
     * corn 表达式
     */
    private String cron;

    /**
     * 任务名
     */
    private String jobName;

    /**
     * 触发器名称
     */
    private String triggerName;

    /**
     * 任务组
     */
    private String jobGroup = Key.DEFAULT_GROUP;

    /**
     * 触发器组
     */
    private String triggerGroup = Key.DEFAULT_GROUP;

    /**
     * 需要传递的数据
     */
    private JobDataMap jobDataMap;

    /**
     * 立即启动
     */
    private boolean eager = false;

    /**
     * 任务描述
     */
    private String description;

    private final Consumer<QuartzJobBuilder> consumer;


    public QuartzJobBuilder(Consumer<QuartzJobBuilder> consumer) {
        this.consumer = consumer;
    }

    /**
     * 从 VO 中获取树形
     *
     * @param job 任务配置
     * @return -
     * @throws SchedulerException - 非法的 class
     */
    public QuartzJobBuilder from(ScheduleJob job) throws SchedulerException {
        this.withJobGroup(job.getJobGroup())
                .withJobName(job.getJobName())
                .withTriggerGroup(job.getTriggerGroup())
                .withTriggerName(job.getTriggerName());

        if (job.getCron() != null) {
            this.withCron(job.getCron());
        }
        if (job.getJobClass() != null) {
            this.ofType(job.getJobClass());
        }
        if (job.getRunnable() != null) {
            this.withRunnable(job.getRunnable());
        }

        return this;
    }

    public Class<? extends Job> getJobClass() {
        return clazz;
    }

    public QuartzJobBuilder ofType(Class<? extends Job> clazz) {
        this.clazz = clazz;
        return this;
    }

    /**
     * 使用全类名转为 Class
     *
     * @param clazz 全类名
     */
    @SuppressWarnings(Warning.UNCHECKED)
    public QuartzJobBuilder ofType(@NotNull String clazz) throws SchedulerException {
        try {
//            cn.seaboot.admin.quartz.smart.CallableJob
            this.clazz = (Class<? extends Job>) Class.forName(clazz);
            if (this.clazz.isAssignableFrom(Job.class)) {
                throw new SchedulerException("It is not instance of Job: " + clazz);
            }
        } catch (ClassNotFoundException e) {
            throw new SchedulerException("Class not found: " + clazz, e);
        }
        return this;
    }

    public String getCron() {
        return cron;
    }

    public QuartzJobBuilder withCron(String cron) {
        this.cron = cron;
        return this;
    }

    /**
     * 设置一次性任务，在指定时间运行
     *
     * @param date 日期
     * @return this
     */
    public QuartzJobBuilder withDateTime(LocalDateTime date) {
        this.cron = date.format(FORMAT);
        return this;
    }

    public String getJobName() {
        return jobName;
    }

    public QuartzJobBuilder withJobName(String jobName) {
        this.jobName = jobName;
        return this;
    }

    public String getTriggerName() {
        return triggerName;
    }

    public QuartzJobBuilder withTriggerName(String triggerName) {
        this.triggerName = triggerName;
        return this;
    }

    public String getJobGroup() {
        return jobGroup;
    }

    public QuartzJobBuilder withGroup(String group) {
        this.jobGroup = group;
        this.triggerGroup = group;
        return this;
    }

    public QuartzJobBuilder withName(String name) {
        this.jobName = name;
        this.triggerName = name;
        return this;
    }

    public QuartzJobBuilder withJobGroup(String jobGroup) {
        this.jobGroup = jobGroup;
        return this;
    }

    public String getTriggerGroup() {
        return triggerGroup;
    }

    public QuartzJobBuilder withTriggerGroup(String triggerGroup) {
        this.triggerGroup = triggerGroup;
        return this;
    }

    public JobDataMap getJobDataMap() {
        return jobDataMap;
    }

    public QuartzJobBuilder withJobDataMap(JobDataMap jobDataMap) {
        this.jobDataMap = jobDataMap;
        return this;
    }

    /**
     * 设置 job 的参数，使用这个函数，可以摆脱对 quartz 的依赖
     *
     * @param params -
     * @return -
     */
    public QuartzJobBuilder withJobDataMap(Map<String, Object> params) {
        this.jobDataMap = new JobDataMap(params);
        return this;
    }

    /**
     * 将回调函数添加到任务参数中
     *
     * @param runnable -
     * @return -
     */
    public QuartzJobBuilder withRunnable(Runnable runnable) {
        this.clazz = CallableJob.class;

        JobDataMap map = new JobDataMap();
        map.put(CallableJob.CALL_KEY, runnable);
        this.jobDataMap = map;
        return this;
    }

    public boolean getEager() {
        return eager;
    }

    /**
     * 是否立即启动
     *
     * @param eager -
     * @return this
     */
    public QuartzJobBuilder withEager(Boolean eager) {
        this.eager = eager;
        return this;
    }

    public String getDescription() {
        return description;
    }

    /**
     * 任务描述
     *
     * @param description -
     * @return this
     */
    public QuartzJobBuilder withDescription(String description) {
        this.description = description;
        return this;
    }

    /**
     * 构建一个任务
     */
    public void build() {
        consumer.accept(this);
    }
}
